/*
 * IDGenerator.cpp
 *
 */

#include "IDGenerator.h"

#include "../exceptions/ProgramException.h"
#include "../utils/types.h"
IDGenerator* IDGenerator::instance = NULL;

IDGenerator::~IDGenerator() {
	this->save();
}

IDGenerator::IDGenerator() {

	//this->nombreSecuenciasUltimaSecuencia = map<string, int>;
}

void IDGenerator::parseSeqFile(ifstream* seqFile) {
	char buffer[MAX_LINE_LENGTH];
	char* seqName;
	int seqLastId;

	while (!seqFile->eof()) {

		//Se lee hasta el fin de linea
		*seqFile >> buffer;
		//si no termino el archivo cargo el estado de la secuencia correspondiente a esa linea
		if (!seqFile->eof()) {
			//obtengo el nombre de la secuencia
			seqName = strtok(buffer, SEQ_FILE_SEPARATOR);
			//obtengo el ultimo id que se obtuvo de la secuencia
			seqLastId = StringUtils::stringToId(
					strtok(NULL, SEQ_FILE_SEPARATOR));
			//actualizo la secuencia con el último id que produjo
			(this->nombreSecuenciasUltimaSecuencia)[seqName] = seqLastId;
		}
	}
}

void IDGenerator::saveSequences(ofstream* seqFile) {
	map<string, int>::const_iterator itSeq;

	//recorro las secuencias y por cada una guardo el ultimo id que produjo en el archivo
	for (itSeq = this->nombreSecuenciasUltimaSecuencia.begin();
			itSeq != this->nombreSecuenciasUltimaSecuencia.end(); ++itSeq)
		*seqFile << itSeq->first << SEQ_FILE_SEPARATOR << itSeq->second << endl;
}

IDGenerator* IDGenerator::getInstance() {

	bool wasLoadedOk = false;
	if (instance == NULL) {
		instance = new IDGenerator();
		wasLoadedOk = instance->loadAll();
		if (!wasLoadedOk) {
			delete instance;
			instance = NULL;
			throw ProgramException("Las secuencias no fueron inicializadas");
		}
	}

	return instance;
}

int IDGenerator::getNextID(const string& sequenceName) {

	if (sequenceName.size() <= 0) {
		throw ProgramException(
				"IDGenerator: el nombre de la secuencia es vacio");
	}
	int value = ++(this->nombreSecuenciasUltimaSecuencia)[sequenceName];
	this->save();
	return value;
}

bool IDGenerator::load(const string& seqFileName) {
	ifstream* seqFile;
	bool wasOpenOk;

	wasOpenOk = false;
	seqFile = new ifstream(seqFileName.c_str());
	wasOpenOk = seqFile->is_open();
	if (!wasOpenOk) {
		ofstream* outseqFile = new ofstream(seqFileName.c_str());
		wasOpenOk = outseqFile->is_open();
		outseqFile->close();
		delete outseqFile;
	} else {
		parseSeqFile(seqFile);
		seqFile->close();
	}
	delete seqFile;

	return wasOpenOk;
}

bool IDGenerator::loadAll() {
	return load(ID_SEQUENCES_FILE);
}

bool IDGenerator::save(const string& seqFileName) {
	ofstream* seqFile;
	bool wasSavedOk;
	wasSavedOk = false;
	seqFile = new ofstream(seqFileName.c_str(), ios::trunc);
	wasSavedOk = seqFile->is_open();
	if (wasSavedOk) {
		saveSequences(seqFile);
		seqFile->close();
		wasSavedOk = true;
	}

	delete seqFile;

	return wasSavedOk;
}

bool IDGenerator::save() {
	return save(ID_SEQUENCES_FILE);
}

void IDGenerator::reset(const string& seqName) {
	(this->nombreSecuenciasUltimaSecuencia)[seqName] = 0;
}

void IDGenerator::resetAll() {
	map<string, int>::const_iterator itSeq;

	//recorro las secuencias y las reseteo
	for (itSeq = this->nombreSecuenciasUltimaSecuencia.begin();
			itSeq != this->nombreSecuenciasUltimaSecuencia.end(); ++itSeq) {
		reset(itSeq->first);
	}
}
